package com.mc.lp.database.service.handler;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;

import javax.annotation.Resource;

import org.springframework.dao.DataAccessException;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import com.mc.lp.database.exception.ConcurrentAccessException;
import com.mc.lp.database.service.handler.constant.FormRequestType;
import com.mc.lp.database.service.handler.event.StudentRecordUpdateEvent;
import com.mc.lp.database.service.handler.event.UserAuditEvent;
import com.mc.lp.database.service.handler.exception.ValidationException;
import com.mc.lp.service.AcademicRecordService;
import com.mc.lp.shared.vo.AcademicRecordVO;
import com.mc.lp.shared.vo.IValueObject;
import com.mc.lp.shared.vo.SearchCriteriaVO;
import com.mc.lp.shared.vo.SimpleResponse;
import com.mc.lp.shared.vo.StudentRecordVO;
/**
 * handler all request related to student records saving and fetching information.
 * @author deepak
 *
 */
public class AcademicRecordHandler extends AbstractFormHandler<IValueObject,IValueObject>{

	//each handler will have a server attached to it to communicate to database.
	@Resource 
	private AcademicRecordService academicRecordService;

	/**
	 * this method will tell how many request this handler can handle
	 */
	public HashSet<FormRequestType> getRequestHandlingType() {
		HashSet<FormRequestType> handledRequest= new HashSet<FormRequestType>();
		handledRequest.add(FormRequestType.SAVE_ACADEMICS);
		handledRequest.add(FormRequestType.GET_ACADEMICS_BY_GRADE_AND_TERM);
		return handledRequest;
	}
	
	@Override
	public IValueObject serveRequest(FormRequestType requestType, IValueObject object) throws DataAccessException, ConcurrentAccessException {
		SimpleResponse response = new SimpleResponse();
		response.setId(1);
		response.setMsg("No case matched to perform operation, please check request type");
		
		switch(requestType){
				case SAVE_ACADEMICS:
					IValueObject saveResult=saveAcademics(requestType,object);
					if(saveResult==null){
						response.setMsg("Input Not Valid, please check posted values");
						return response;
					}
					return saveResult;
				case GET_ACADEMICS_BY_GRADE_AND_TERM:
					if(object instanceof StudentRecordVO){
						StudentRecordVO studentVoForSearch= (StudentRecordVO)object;
						IValueObject returnedObject= getAcademicRecordService().getAcademicsRecordsByEntityIdTermGrade(studentVoForSearch);
						return returnedObject;
					}else{
						response.setMsg("Wrong VO Passed to thid method it should be StudentRecordVO");
					}
					break;
					default:
						return response;
		}
		return response;
	}
	
	/**
	 * method helps in saving academics records.
	 * @param requestType
	 * @param object
	 * @return
	 * @throws DataAccessException
	 * @throws ConcurrentAccessException
	 */
	public IValueObject saveAcademics(FormRequestType requestType, IValueObject object) throws DataAccessException, ConcurrentAccessException{
		if(object instanceof StudentRecordVO){
			StudentRecordVO studentRecordVo= (StudentRecordVO)object;
			IValueObject returnedObject= getAcademicRecordService().saveAcademics(studentRecordVo);
			
			//fire event that academics has been updated by user, and notify student update event handler
			UserAuditEvent event = new UserAuditEvent();
			StudentRecordUpdateEvent studentUpdateEvent= new StudentRecordUpdateEvent();
			
			getAcademicRecordService().fireEvent(event);
			getAcademicRecordService().fireEvent(studentUpdateEvent);
			
			return returnedObject;
		}else{
			return null;
		}
	}
	
	public List<Exception> validateRequest(FormRequestType requestType, IValueObject v) {
		List<Exception> validationExceptions = new ArrayList<Exception>();
		if(v instanceof StudentRecordVO){
			StudentRecordVO vo = (StudentRecordVO)v;
			SearchCriteriaVO searchCriteria=vo.getSearchCriteria();
			switch (requestType) {
			case SAVE_ACADEMICS:
				if(searchCriteria.getStudentEntityId()==null || searchCriteria.getStudentEntityId()==0){
					validationExceptions.add(new ValidationException("StudentEntityId","Entity Id is null,It must contain a entity id."));
				}
				if(searchCriteria.getGradeId()<=0){
					validationExceptions.add(new ValidationException("Grade","Must Give Student Class Name"));
				}
				if(searchCriteria.getTermId()<=0){
					validationExceptions.add(new ValidationException("Term","Must Give Student Examination Term"));
				}
				List<AcademicRecordVO> academicVoList= vo.getStudentAcademics();
				if(CollectionUtils.isEmpty(academicVoList)){
					validationExceptions.add(new ValidationException("Academic Record","Must Contain Atleast one row to save"));
				}else{
					//loop each row to check validations
					for(AcademicRecordVO academicRecord:academicVoList){
						if(academicRecord.getSubjectId()==null || academicRecord.getSubjectId()<=0){
							validationExceptions.add(new ValidationException("Subject" +academicRecord.getSid(),"Must Enter Value for subject"));
						}
						if((academicRecord.getMarks()==null || academicRecord.getMarks()<=0) && StringUtils.isEmpty(academicRecord.getGradePointId()<=0)){
							validationExceptions.add(new ValidationException("Marks" +academicRecord.getSid(),"Must give value for atleast one; marks or grade"));
						}
						if(academicRecord.getMaxMarks()==null || academicRecord.getMaxMarks()<=0){
							validationExceptions.add(new ValidationException("Max Marks" +academicRecord.getSid(),"Maximum Marks Not defined"));
						}
					}
				}
				break;
			case GET_ACADEMICS_BY_GRADE_AND_TERM:
				if(searchCriteria.getStudentEntityId()==null || searchCriteria.getStudentEntityId()==0){
					validationExceptions.add(new ValidationException("StudentEntityId","Entity Id is null,It must contain a entity id."));
				}
				if(searchCriteria.getGradeId()<=0){
					validationExceptions.add(new ValidationException("Grade","Must Give Student Class Name"));
				}
				if(searchCriteria.getTermId()<=0){
					validationExceptions.add(new ValidationException("Term","Must Give Student Examination Term"));
				}
				break;
			}
		}
		return validationExceptions;
	}

	public AcademicRecordService getAcademicRecordService() {
		return academicRecordService;
	}

	public void setAcademicRecordService(AcademicRecordService academicRecordService) {
		this.academicRecordService = academicRecordService;
	}

	
	
}
